<?php

namespace app\api\controller;

use app\common\controller\Api;
use think\Cache;
use think\Exception;
use think\exception\PDOException;
use think\exception\ValidateException;
use \app\common\library\Sms;
use \think\Log;
use EasyWeChat\Factory;
use think\Db;

class Payment extends Api
{
    protected $noNeedLogin = ['*'];
    protected $noNeedRight = ['*'];
    protected $needUserLogin = ['pay', 'secondPay'];
    //Token默认有效时长
    protected $keeptime = 0;
    //easyConfig
    protected $_token = '';
    protected $config = [
        // 必要配置
        'app_id' => 'wxb2f4f9b7e792c428',
        'mch_id' => '1601366441',
        'key' => 'KsQa3ZYqA0vMic8d7G9kr6VgpHhLUPt4',   // API 密钥
        // 如需使用敏感接口（如退款、发送红包等）需要配置 API 证书路径(登录商户平台下载 API 证书)
        //'cert_path' => 'path/to/your/cert.pem', // XXX: 绝对路径！！！！
        //'key_path' => 'path/to/your/key',      // XXX: 绝对路径！！！！

    ];
    protected $miniConfig = [
        'app_id' => 'wxb2f4f9b7e792c428',
        'secret' => '652aa06f7ac713b380eed4d3bc008cae',
        // 指定 API 调用返回结果的类型：array(default)/collection/object/raw/自定义类名
        'response_type' => 'array',
        //...
    ];

    /**
     * 首页
     *
     */
    public function index()
    {
        $this->success('请求成功');
    }

    /**
     * 发起支付
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \GuzzleHttp\Exception\GuzzleException
     * @throws Exception
     */
    public function pay()
    {
        if ($this->request->isPost()) {

            $data = (array)$this->_data;

            //发起支付
            $workerId = trim($this->request->post('worker_id'));
            $couponId = trim($this->request->post('coupon_id'));
            $villageId = trim($this->request->post('village_id'));
            $addressDetail = trim($this->request->post('address_detail'));
            $addressPhone = trim($this->request->post('address_phone'));
            $serviceName = trim($this->request->post('service_name'));
            $area = trim($this->request->post('area'));
            $remark = trim($this->request->post('remark'));
            $appointmenttime = trim($this->request->post('appointmenttime'));
            $mainImage = trim($this->request->post('main_image'));
            $addressName = trim($this->request->post('address_name'));


            $result = $this->validate(['worker_id' => $workerId,
                'coupon_id' => $couponId,
                'village_id' => $villageId,
                'address_detail' => $addressDetail,
                'address_phone' => $addressPhone,
                'service_name' => $serviceName,
                'area' => $area,
                'remark' => $remark,
                'address_name' => $addressName,
                'appointmenttime' => $appointmenttime], 'Payment');

            if (true !== $result) {
                // 验证失败 输出错误信息
                $this->error($result, [], 201);
            }


            //根据service_name查询service表 和 给你的area参数 计算价格
            $service = Db::table('fa_service')
                ->where('name', $serviceName)
                ->find();

            if (!$service) {
                $this->success('没有此服务', [], 201);
            }


            //单位为元
            $costPrice = round($service['price'] * $area, 2);


            //优惠券
            $couponFee = 0;

            if ($couponId) {

                $userCoupon = Db::table('fa_user_coupon')
                    ->where('id', $couponId)
                    ->where('user_id', $data['user_id'])
                    ->where('endtime', '>', time())
                    ->where('status', 0)
                    ->find();
                if (!$userCoupon) {
                    $this->success('优惠券不存在', [], 201);
                }
                $coupon = Db::table('fa_coupon')
                    ->where('id', $userCoupon['coupon_id'])
                    ->find();
                if ($coupon['with_amout'] * 100 > $coupon) {

                    $this->success('订单金额不满足满减条件', [], 201);

                }

                $couponFee = $coupon['fee'];

            }

            $fee = $costPrice - $couponFee;


            //根据worker_id和appointmenttime查询此员工是否有档期
            $workerIds = explode(",", $workerId);

            $startTime = $appointmenttime;

            $endTime = $appointmenttime + ($area / $service['speed'] * 60 * 60 / count($workerIds) + 30 * 60);


            foreach ($workerIds as $key => $item) {

                $exist = Db::table('fa_worker_calendar')
                    ->where('worker_id', $item)
                    ->where($startTime . ' between starttime and endtime OR ' . $endTime . ' between starttime and endtime')
                    ->where('date', date('Y-m-d', $appointmenttime))
                    ->find();

                if ($exist) {
                    $this->success('此员工在这个时间无法完成该服务', [], 201);
                }

            }

            //创建订单号
            $orderNo = date('Ymd') . str_pad(mt_rand(10000, 99999), 5, '0', STR_PAD_LEFT);

            //订单表中创建一条订单记录
            $result = Db::table('fa_order')->insert([
                'id' => $orderNo,
                'user_id' => $data['user_id'],
                'worker_id' => $workerId,
                'user_coupon_id' => $couponId ? $couponId : null,
                'village_id' => $villageId,
                'address_detail' => $addressDetail,
                'address_phone' => $addressPhone,
                'service_name' => $serviceName,
                'area' => $area,
                'main_image' => $mainImage,
                'cost_price' => $costPrice,
                'remark' => $remark,
                'status' => 0,
                'address_name' => $addressName,
                'appointmenttime' => $appointmenttime,
                'createtime' => time(),
                'unit_price' => $service['price']
            ]);

            if (!$result) {

                $this->error('创建订单失败', [], 201);

            }

            //修改用户优惠券表状态
            if ($couponId) {
                Db::table('fa_user_coupon')
                    ->where('id', $couponId)
                    ->update(['status' => 1]);
            }

            $openId = Db::table('fa_user')
                ->where('id', $data['user_id'])
                ->value('openid');

            //调用微信支付统一下单接口
            $app = Factory::payment($this->config);

            $result = $app->order->unify([
                'body' => '大拇指生活-' . $serviceName,
                'out_trade_no' => $orderNo,
                'total_fee' => $fee * 100,//单位为分
                'notify_url' => '139.9.139.79/api/payment/notify', // 支付结果通知网址，如果不设置则会使用配置里的默认地址
                'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型
                'openid' => $openId]);

            if ($result['return_code'] != 'SUCCESS' || $result['result_code'] != 'SUCCESS') {

                $this->error($result['return_msg'], [], 201);

            }

            //redis存储
            Cache::set($orderNo, $result, 15 * 60);


            //生成js支付配置
            $jssdk = $app->jssdk;

            $config = $jssdk->bridgeConfig($result['prepay_id'], false);

            $this->success('ok', $config, 200);
        }
    }


    /**
     * 二次支付
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\db\exception\DataNotFoundException
     */
    public function secondPay()
    {
        if ($this->request->isPost()) {

            $id = trim($this->request->post('id'));
            $data = (array)$this->_data;

            if (!$id) {

                $this->success('缺少必要参数', [], 201);

            }


            $order = Db::table('fa_order')
                ->where('user_id', $data['user_id'])
                ->where('id', $id)
                ->find();

            if (!$order) {
                $this->success('未查询到此订单', [], 201);
            }

            $result = Cache::get($id);

            if (!$result) {

                $this->error('未在缓存中查询到数据', [], 201);

            }

            //根据worker_id和appointmenttime查询此员工是否有档期

            $service = Db::table('fa_service')
                ->where('name', $order['service_name'])
                ->find();

            $workerIds = explode(",", $order['worker_id']);

            $startTime = $order['appointmenttime'];

            $endTime = $order['appointmenttime'] + ($order['area'] / $service['speed'] * 60 * 60 / count($workerIds) + 30 * 60);

            foreach ($workerIds as $key => $workerId) {

                $exist = Db::table('fa_worker_calendar')
                    ->where('worker_id', $workerId)
                    ->where($startTime . ' between starttime and endtime OR ' . $endTime . ' between starttime and endtime')
                    ->where('date', date('Y-m-d', $order['appointmenttime']))
                    ->find();
                if ($exist) {
                    $this->success('此员工在这个时间无法完成该服务', [], 201);
                }
            }

            $app = Factory::payment($this->config);

            //生成js支付配置
            $jssdk = $app->jssdk;

            $config = $jssdk->bridgeConfig($result['prepay_id'], false);

            $this->success('ok', $config, 200);

        }


    }

    /**
     * @throws \EasyWeChat\Kernel\Exceptions\Exception
     */
    public function notify()
    {
        if ($this->request->isPost()) {

            $app = Factory::payment($this->config);

            $response = $app->handlePaidNotify(function ($message, $fail) {

                $order = Db::table('fa_order')
                    ->where('id', $message['out_trade_no'])
                    ->find();


                if (!$order || $order['status'] != 0) { // 如果订单不存在 或者 订单已经支付过了

                    Log::error('Order not exists or have paid.');

                    $fail('Order not exists or have paid.');

                    return false;
                }

                if ($message['return_code'] === 'SUCCESS') { // return_code 表示通信状态，不代表支付状态

                    if ($message['result_code'] === 'SUCCESS') { // 用户是否支付成功

                        Log::error($message);

                        $paytime = time();

                        //更新订单状态
                        $data = ['id' => $message['out_trade_no'],
                            'status' => 1,
                            'pay_price' => round($message['total_fee'] / 100, 2),
                            'paytime' => $paytime];

                        Db::table('fa_order')
                            ->update($data);


                        //添加员工档期表
                        $speed = Db::table('fa_service')
                            ->where('name', $order['service_name'])
                            ->value('speed');


                        $workerIds = explode(",", $order['worker_id']);

                        $data = ['order_id' => $message['out_trade_no'],
                            'worker_id' => null,
                            'date' => date('Y-m-d', $order['appointmenttime']),
                            'starttime' => $order['appointmenttime'],
                            'endtime' => date($order['appointmenttime'] + ($order['area'] / $speed * 60 * 60 / count($workerIds) + 30 * 60))];

                        foreach ($workerIds as $key => $workerId) {
                            $data['worker_id'] = $workerId;
                            Db::table('fa_worker_calendar')
                                ->insert($data);
                        }

                        //详细地址
                        $village = Db::table('fa_village')
                            ->field('city,districts,village')
                            ->where('id', $order['village_id'])
                            ->find();

                        $addressDetail = $village['city'] . $village['districts'] . $village['village'] . $order['address_detail'];
                        //下发订阅消息给用户
                        $data = [
                            'template_id' => 'PH2_4Q19REBV8Dzec6igXdWfB-c_UZC5c3v5fYu7Mb8', // 所需下发的订阅模板id
                            'touser' => $message['openid'],     // 接收者（用户）的 openid
                            'page' => '/pages/order/detail?id=' . $message['out_trade_no'],       // 点击模板卡片后的跳转页面，仅限本小程序内的页面。支持带参数,（示例index?foo=bar）。该字段不填则模板无跳转。
                            'data' => [         // 模板内容，格式形如 { "key1": { "value": any }, "key2": { "value": any } }
                                'character_string22' => [
                                    'value' => $order['id'],
                                ],
                                'time1' => [
                                    'value' => date('H:i', $order['appointmenttime']),
                                ],
                                'name15' => [
                                    'value' => $order['service_name'],
                                ],
                                'amount26' => [
                                    'value' => '￥' . $order['pay_price'] / 100,
                                ],
                                'thing9' => [
                                    'value' => $addressDetail,
                                ],
                            ],
                        ];

                        $mini = Factory::miniProgram($this->miniConfig);

                        $mini->subscribe_message->send($data);

                        //给工人下发语音电话通知

                        foreach ($workerIds as $key => $workerId) {
                            $phone = Db::table('fa_worker')
                                ->where('id', $workerId)
                                ->value('mobile');
                            Sms::txSendMsgVoice($phone);
                        }

                        Cache::rm($order['id']);
                    }
                } elseif ($message['result_code'] === 'FAIL') {

                    Log::error('Order result error.' . $order);

                    $fail('Order result error.');


                } else {

                    return false;
                }
                // 或者错误消息
                $fail('Order not exists.');
            });
            $response->send();
        }
    }


}


